Skip to main content
Version: 6.4.0

read <src>

Added in 6.4.0.

contract.read is a typed, ergonomic namespace that exposes a contract's view / pure (and legacy constant) functions. A read is executed through triggerConstantContract, does not modify the chain, costs nothing, and resolves directly to the decoded result.

State-changing functions live in the write namespace instead. When the ABI is declared as const, function names and argument types are checked at compile time. This is the recommended alternative to the flat .call() surface.

note

Every namespace method is async. All validation (argument count, call value, …) surfaces as a promise rejection, never a synchronous throw — always await the call.

Usage

// Signature (each method on the namespace)
contract.read.<fn>(args: unknown[], options?: ReadOptions): Promise<Decoded>
contract.read.<fn>(options?: ReadOptions): Promise<Decoded> // for a no-argument method

type ReadOptions = { from?: string; value?: number | bigint };
const abi = [...] as const;
const contract = tronWeb.contract(abi, 'contractAddress');

// resolves to the decoded return value
const result = await contract.read.methodName([arg0, arg1, ...], options);

The first positional argument is the array of method arguments. For a method that takes no arguments you may pass nothing, or pass the options object directly:

await contract.read.totalSupply();           // no args
await contract.read.totalSupply(options); // no args, with options
await contract.read.balanceOf([owner]); // one arg

Parameters

ParameterDescriptionType
argsArray of the method's arguments, in ABI order. Addresses may be base58 or hex. Omit for a no-arg method.unknown[]
optionsOptional. Call options (see below).object

read options

OptionDescriptionType
fromThe caller (issuer) address for the constant call (base58 or hex). Falls back to the instance's default address.string
valueTRX (in sun) attached to the call (callValue).number | bigint

A caller address is required: pass from, or set a default address on the TronWeb instance — if neither is set the call rejects (it is not issued from a zero address). To issue/sign as a specific account, use the write namespace's account (private key) option; account is write-only and is not accepted by read.

Returns

The decoded output. A single output is collapsed to the bare value (e.g. a uint256 resolves to a bigint); multiple outputs resolve to an array. A function that declares no outputs resolves to undefined; a function that declares outputs but returns no data rejects with Failed to execute.

Selector form (overloads)

Each function is additionally exposed under its full selector, e.g. contract.read['balanceOf(address)']. The selector form pins that exact overload, so same-arity overloads can be addressed unambiguously:

const balance = await contract.read['balanceOf(address)'](['TXXX...']);

When two overloads share the same arity, the bare name cannot pick one and the call rejects with Ambiguous overloaded function "<name>" ... — use the selector key to disambiguate.

tip

The selector key is a function's canonical signature — its name followed by the parenthesized input types in canonical form (bare uint / int widen to uint256 / int256, tuples flatten to (type,…); trcToken is kept as-is per the TVM convention). Rather than hand-writing it, derive it from an ABI fragment with tronWeb.utils.abi.buildFunctionSelector — it returns this exact string, the same value the namespace registers internally:

const fragment = abi.find((f) => f.name === 'balanceOf');
const key = tronWeb.utils.abi.buildFunctionSelector(fragment); // 'balanceOf(address)'
await contract.read[key](['TXXX...']);
note

Namespaces enumerate each method under both its bare name and its selector, so Object.keys(contract.read) returns two entries per function:

Object.keys(contract.read);   // ['balanceOf', 'balanceOf(address)']

Functions named read

If the ABI literally defines a function called read, it stays callable through the legacy flat surface, and the namespace is served from the same object — so both work:

await contract.read().call();   // legacy flat call → triggerSmartContract
await contract.read.read(); // namespace entry → triggerConstantContract

Validation & errors

All of the following reject the returned promise:

ConditionError message
Wrong number of argumentsContract function "<name>" expects <n> argument(s) but received <m>.
Ambiguous same-arity overload (bare name)Ambiguous overloaded function "<name>" for the given arguments; pass the full signature ...
Calling read on a state-changing functionFunction "<name>" is not read-only.
from is not a valid addressThe "from" option must be a valid address.
No caller address (from unset and no default)A caller address is required. Set the "from" option or a default address on the TronWeb instance.
A function with declared outputs returns no dataFailed to execute
Invalid valuecall value cannot be negative / call value must be an integer / call value exceeds safe integer range / call value must be a number or bigint

Example

const abi = [
{
type: 'function',
name: 'balanceOf',
stateMutability: 'view',
inputs: [{ name: 'owner', type: 'address' }],
outputs: [{ name: 'balance', type: 'uint256' }],
},
] as const;

async function demo() {
const contract = tronWeb.contract(abi, 'TContractAddress...');

// only `view` / `pure` functions appear here
const balance = await contract.read.balanceOf(['TOwnerAddress...']);
console.log(balance);
42n

// override the caller (issuer) address explicitly, plus a call value (in sun)
await contract.read.balanceOf(['TOwnerAddress...'], { from: 'TCallerAddress...', value: 3n });
}
demo();

See also the write namespace and the flat call() surface.